package com.hhy.lombok.processor;

import com.hhy.lombok.annotation.Data;
import com.hhy.lombok.utils.JCUtils;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;

import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.lang.annotation.Annotation;
import java.util.Set;

import static com.hhy.lombok.utils.JCUtils.getJClassFields;
import static com.hhy.lombok.utils.ProcessUtils.*;
import static com.hhy.lombok.constant.Constant.*;
import static com.sun.tools.javac.util.List.of;

@SupportedAnnotationTypes("com.hhy.lombok.annotation.Data")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class DataProcessor extends BaseProcessor {

    /**
     * 类的语法树节点
     */
    private JCTree.JCClassDecl jcClass;

    @Override
    public void doProcess(Element element) {
        JCTree jcTree = trees.getTree(element);
        jcTree.accept(new TreeTranslator() {
            @Override
            public void visitClassDef(JCTree.JCClassDecl jcClass) {
                treeMaker.at(jcClass.pos);
                jcClass.defs = jcClass.defs.appendList(
                        createDataMethods(jcClass)
                );
                log.log(jcClass, "generated getter/setter method");
            }
        });
    }

    /**
     * 创建get/set方法
     *
     * @return get/set方法的语法树节点集合
     */
    private List<JCTree> createDataMethods(JCTree.JCClassDecl jcClass) {
        ListBuffer<JCTree> dataMethods = new ListBuffer<>();

        for (JCTree.JCVariableDecl jClassField : getJClassFields(jcClass)) {
            if (!jClassField.mods.getFlags().contains(Modifier.FINAL)
                    && !hasSetMethod(jClassField, jcClass)) {
                dataMethods.append(createSetJCMethod(jClassField));
            }

            if (!hasGetterMethod(jClassField, jcClass)) {
                dataMethods.append(createGetJCMethod(jClassField));
            }
        }

        return dataMethods.toList();
    }

    /**
     * 创建set方法
     */
    private JCTree.JCMethodDecl createSetJCMethod(JCTree.JCVariableDecl jcVariable) {
        // 添加语句 " this.xxx = xxx; "
        JCTree.JCBlock jcBlock = JCUtils.createBlock(treeMaker,
                of(JCUtils.createAssignStatement(treeMaker, treeMaker.Ident(names.fromString(THIS)), jcVariable.name, treeMaker.Ident(jcVariable.name))));
        return JCUtils.createMethod(
                treeMaker,
                names.fromString(toSetterMethodName(jcVariable.name.toString())),
                treeMaker.TypeIdent(TypeTag.VOID),
                List.of(cloneJCVariableAsParam(treeMaker, jcVariable)),
                List.nil(),
                jcBlock,
                Flags.PUBLIC
        );
    }

    /**
     * 创建get方法
     * @param jcVariable 字段的语法树节点
     * @return get方法的语法树节点
     */
    private JCTree.JCMethodDecl createGetJCMethod(JCTree.JCVariableDecl jcVariable) {
        // 添加语句 " return this.xxx; "
        JCTree.JCBlock jcBlock = JCUtils.createBlock(
                treeMaker
                , of(JCUtils.createReturn(treeMaker,
                                treeMaker.Ident(names.fromString(THIS)), jcVariable.name, null))
        );
        return JCUtils.createMethod(
                treeMaker,
                names.fromString(toGetterMethodName(jcVariable.name.toString())),
                jcVariable.vartype,
                List.nil(),
                List.nil(),
                jcBlock,
                Flags.PUBLIC
        );
    }

    @Override
    protected Class<? extends Annotation> getNeedToHandleAnnotation() {
        return Data.class;
    }
}
